<?php
/**
 * 公共函数库.
 * 
 * 
 * 其中有部分函数来源于第三方开源库.如wordpress等.
 * 
 * @author Leo Ning <leo.ning@like18.com>
 * @copyright LIKE18 INC. 2008 - 2011
 * @version 1.0
 * @since 1.0
 * @package utils
 * @subpackage functions
 */
// 定义lcfirst
if (! function_exists ( 'lcfirst' )) {
	/**
	 * 将字符串第一个字母小写
	 *
	 * @param string $str        	
	 * @return string
	 */
	function lcfirst($str) {
		return strtolower ( substr ( $str, 0, 1 ) ) . substr ( $str, 1 );
	}
}
/**
 * 
 * 得到系统提供的文件系统,如果未提供，则返回false.
 * @return FileSystem 可以使用的文件系统
 */
function getFileSystem() {
	static $__fs = null;
	if (is_null ( $__fs )) {
		$__fs = apply_filter ( 'get_filesystem', null );
	}
	if ($__fs instanceof FileSystem) {
		return $__fs;
	}
	return false;
}
function thefilename($filename) {
	$encode = mb_detect_encoding ( $filename, "UTF-8,GBK,GB2312,BIG5,ISO-8859-1" );
	if ($encode != 'UTF-8') {
		$filename = mb_convert_encoding ( $filename, "UTF-8", $encode );
	}
	return $filename;
}
/**
 * Set HTTP status header.
 *
 * @since 1.0
 * 
 * @param int $header
 * HTTP status code
 * @return null Does not return anything.
 */
function status_header($header) {
	$text = get_status_header_desc ( $header );
	
	if (empty ( $text )) {
		return false;
	}
	$protocol = $_SERVER ["SERVER_PROTOCOL"];
	if ('HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol) {
		$protocol = 'HTTP/1.0';
	}
	$status_header = "$protocol $header $text";
	
	return @header ( $status_header, true, $header );
}
/**
 * Retrieve the description for the HTTP status.
 *
 * @since 1.0
 * 
 * @param int $code
 * HTTP status code.
 * @return string Empty string if not found, or description if found.
 */
function get_status_header_desc($code) {
	global $output_header_to_desc;
	
	$code = abs ( intval ( $code ) );
	
	if (! isset ( $output_header_to_desc )) {
		$output_header_to_desc = array (100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 

		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 226 => 'IM Used', 

		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Reserved', 307 => 'Temporary Redirect', 

		400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 426 => 'Upgrade Required', 

		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 510 => 'Not Extended' );
	}
	
	if (isset ( $output_header_to_desc [$code] ))
		return $output_header_to_desc [$code];
	else
		return '';
}
/**
 * Appends a trailing slash.
 *
 * Will remove trailing slash if it exists already before adding a trailing
 * slash. This prevents double slashing a string or path.
 *
 * The primary use of this is for paths and thus should be used for paths. It is
 * not restricted to paths and offers no specific path support.
 *
 * @uses untrailingslashit() Unslashes string if it was slashed already.
 * 
 * @param string $string
 * What to add the trailing slash to.
 * @return string String with trailing slash added.
 */
function trailingslashit($string) {
	return untrailingslashit ( $string ) . '/';
}
/**
 * Removes trailing slash if it exists.
 *
 * The primary use of this is for paths and thus should be used for paths. It is
 * not restricted to paths and offers no specific path support.
 *
 *
 * @param string $string
 * What to remove the trailing slash from.
 * @return string String without the trailing slash.
 */
function untrailingslashit($string) {
	return rtrim ( $string, '/\\' );
}
/**
 * Test if a give filesystem path is absolute ('/foo/bar', 'c:\windows').
 *
 *
 * @param string $path
 * File path
 * @return bool True if path is absolute, false is not absolute.
 */
function path_is_absolute($path) {
	// this is definitive if true but fails if $path does not exist or contains
	// a symbolic link
	if (realpath ( $path ) == $path)
		return true;
	
	if (strlen ( $path ) == 0 || $path {0} == '.')
		return false;
	
		// windows allows absolute paths like this
	if (preg_match ( '#^[a-zA-Z]:\\\\#', $path ))
		return true;
	
		// a path starting with / or \ is absolute; anything else is relative
	return ( bool ) preg_match ( '#^[/\\\\]#', $path );
}
/**
 * Join two filesystem paths together (e.g.
 * 'give me $path relative to $base').
 *
 * If the $path is absolute, then it the full path is returned.
 *
 *
 * @param string $base        	
 * @param string $path        	
 * @return string The path with the base or absolute path.
 */
function path_join($base, $path) {
	if (path_is_absolute ( $path ))
		return $path;
	
	return rtrim ( $base, '/' ) . '/' . ltrim ( $path, '/' );
}
/**
 * Sanitizes a filename replacing whitespace with dashes
 *
 * Removes special characters that are illegal in filenames on certain
 * operating systems and special characters requiring special escaping
 * to manipulate at the command line. Replaces spaces and consecutive
 * dashes with a single dash. Trim period, dash and underscore from beginning
 * and end of filename.
 *
 * @since 2.1.0
 * 
 * @param string $filename
 * The filename to be sanitized
 * @return string The sanitized filename
 */
function sanitize_file_name($filename) {
	$filename_raw = $filename;
	$special_chars = array ("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", chr ( 0 ) );
	$filename = str_replace ( $special_chars, '', $filename );
	$filename = preg_replace ( '/[\s-]+/', '-', $filename );
	$filename = trim ( $filename, '.-_' );
	// Split the filename into a base and extension[s]
	$parts = explode ( '.', $filename );
	// Return if only one extension
	if (count ( $parts ) <= 2)
		return $filename;
	
		// Process multiple extensions
	$filename = array_shift ( $parts );
	$extension = array_pop ( $parts );
	
	$mimes = array ('tmp', 'txt', 'jpg', 'gif', 'png', 'rar', 'zip', 'gzip', 'ppt' );
	
	// Loop over any intermediate extensions. Munge them with a trailing
	// underscore if they are a 2 - 5 character
	// long alpha string not in the extension whitelist.
	foreach ( ( array ) $parts as $part ) {
		$filename .= '.' . $part;
		
		if (preg_match ( '/^[a-zA-Z]{2,5}\d?$/', $part )) {
			$allowed = false;
			foreach ( $mimes as $ext_preg => $mime_match ) {
				$ext_preg = '!(^' . $ext_preg . ')$!i';
				if (preg_match ( $ext_preg, $part )) {
					$allowed = true;
					break;
				}
			}
			if (! $allowed)
				$filename .= '_';
		}
	}
	$filename .= '.' . $extension;
	
	return $filename;
}
/**
 * Get a filename that is sanitized and unique for the given directory.
 *
 * If the filename is not unique, then a number will be added to the filename
 * before the extension, and will continue adding numbers until the filename is
 * unique.
 *
 * The callback must accept two parameters, the first one is the directory and
 * the second is the filename. The callback must be a function.
 *
 * @param string $dir        	
 * @param string $filename        	
 * @param string $unique_filename_callback
 * Function name, must be a function.
 * @return string New filename, if given wasn't unique.
 */
function wp_unique_filename($dir, $filename, $unique_filename_callback = null) {
	// sanitize the file name before we begin processing
	$filename = sanitize_file_name ( $filename );
	
	// separate the filename into a name and extension
	$info = pathinfo ( $filename );
	$ext = ! empty ( $info ['extension'] ) ? '.' . $info ['extension'] : '';
	$name = basename ( $filename, $ext );
	
	// edge case: if file is named '.ext', treat as an empty name
	if ($name === $ext)
		$name = '';
	
		// Increment the file number until we have a unique file to save in
	// $dir. Use $override['unique_filename_callback'] if supplied.
	if ($unique_filename_callback && is_callable ( $unique_filename_callback )) {
		$filename = $unique_filename_callback ( $dir, $name );
	} else {
		$number = '';
		
		// change '.ext' to lower case
		if ($ext && strtolower ( $ext ) != $ext) {
			$ext2 = strtolower ( $ext );
			$filename2 = preg_replace ( '|' . preg_quote ( $ext ) . '$|', $ext2, $filename );
			
			// check for both lower and upper case extension or image sub-sizes
			// may be overwritten
			while ( file_exists ( $dir . "/$filename" ) || file_exists ( $dir . "/$filename2" ) ) {
				$new_number = $number + 1;
				$filename = str_replace ( "$number$ext", "$new_number$ext", $filename );
				$filename2 = str_replace ( "$number$ext2", "$new_number$ext2", $filename2 );
				$number = $new_number;
			}
			return $filename2;
		}
		
		while ( file_exists ( $dir . "/$filename" ) ) {
			if ('' == "$number$ext")
				$filename = $filename . ++ $number . $ext;
			else
				$filename = str_replace ( "$number$ext", ++ $number . $ext, $filename );
		}
	}
	
	return $filename;
}
/**
 * Returns a filename of a Temporary unique file.
 * Please note that the calling function must unlink() this itself.
 *
 * The filename is based off the passed parameter or defaults to the current
 * unix timestamp,
 * while the directory can either be passed as well, or by leaving it blank,
 * default to a writable temporary directory.
 *
 *
 * @param string $filename
 * (optional) Filename to base the Unique file off
 * @param string $dir
 * (optional) Directory to store the file in
 * @return string a writable filename
 */
function wp_tempnam($filename = '', $dir = '') {
	if (empty ( $dir ))
		$dir = trailingslashit ( TMP );
	$filename = basename ( $filename );
	if (empty ( $filename ))
		$filename = time ();
	
	$filename = preg_replace ( '|\..*$|', '.tmp', $filename );
	$filename = $dir . wp_unique_filename ( $dir, $filename );
	touch ( $filename );
	return $filename;
}

/**
 * 查找文件
 *
 * @param string $dir
 * 起始目录
 * @param string $pattern
 * 合法的正则表达式,此表达式只用于文件名
 * @param array $excludes
 * 不包含的目录名
 * @param boolean $recursive
 * 是否递归查找
 * @param int $stop
 * 递归查找层数
 * @return array 查找到的文件
 */
function find_files($dir = '.', $pattern = '', $excludes = array(), $recursive = 0, $stop = 0) {
	$files = array ();
	$dir = trailingslashit ( $dir );
	if (is_dir ( $dir )) {
		$fhd = @opendir ( $dir );
		if ($fhd) {
			$excludes = is_array ( $excludes ) ? $excludes : array ();
			$_excludes = array_merge ( $excludes, array ('.', '..' ) );
			while ( ($file = readdir ( $fhd )) !== false ) {
				if ($recursive && is_dir ( $dir . $file ) && ! in_array ( $file, $_excludes )) {
					if ($stop == 0 || $recursive <= $stop) {
						$files = array_merge ( $files, find_files ( $dir . $file, $pattern, $excludes, $recursive + 1, $stop ) );
					}
				}
				if (is_file ( $dir . $file ) && @preg_match ( $pattern, $file )) {
					$files [] = $dir . $file;
				}
			}
			@closedir ( $fhd );
		}
	}
	return $files;
}
/**
 * 历史记录操作
 *
 * 访问历史,如果$url为空,则获取$history指定的URL,否则设置历史
 *
 * @uses sess_get 从Session中读取$history的历史记录
 * @uses sess_add 设置$history对应的历史记录
 * @param string $history
 * 历史年代(名称)
 * @param string $url
 * 历史URL
 * @return string void
 */
function history($history = 'back', $url = '') {
	if (empty ( $url )) {
		$url = sess_get ( 'history_' . $history, defined ( 'BASE_URL' ) && BASE_URL ? trailingslashit ( BASE_URL ) : '/' );
	} else {
		sess_add ( 'history_' . $history, $url );
	}
	return $url;
}

/**
 * 取解析后的php文件内容
 *
 * 以{@link WEBROOT}为根目录查找$file,然后执行php文件并返回执行后的内容.
 *
 * @param string $file        	
 * @param array $vars        	
 * @return string
 */
function pfile_get_contents($file, $vars = array()) {
	$content = false;
	$file = trailingslashit ( WEBROOT ) . $file;
	if (is_readable ( $file )) {
		@extract ( $vars );
		@ob_start ();
		@include $file;
		$content = @ob_get_contents ();
		@ob_end_clean ();
	}
	return $content;
}
/**
 * 返回数组的最后一个元素
 *
 * @param array $array        	
 * @return mixed
 */
function array_last($array) {
	if (! empty ( $array ) && is_array ( $array )) {
		return $array [count ( $array ) - 1];
	}
}
/**
 * 请求信息
 *
 * 包括请求人的IP,来源等信息.
 *
 * @global array 框架配置
 * @global Request 请求实例
 * @see Request::clientinfo
 * @param string $name 请求的值，可以是:ip,url,port,referer,city,idc,county      	
 * @return mixed 请求信息
 */
function rinfo($name = '') {
	global $cfg_opts, $__rqst;
	if (! isset ( $cfg_opts ['rinfo'] )) {
		if ($__rqst == null) {
			$__rqst = new Request ( false );
		}
		$cfg_opts ['rinfo'] = $__rqst->clientinfo ();
	}
	if (! empty ( $name )) {
		return isset($cfg_opts ['rinfo'] [$name])?$cfg_opts ['rinfo'] [$name]:null;
	} else {
		return $cfg_opts ['rinfo'];
	}
}
/**
 * 读取请求数据
 *
 * 如果请求中没有$name,则返回$default
 *
 * @global array 框架配置
 * @global Request 请求实例
 * @see Request::get
 * @param string $name        	
 * @param mixed $default        	
 * @param boolean $xss_clean        	
 * @return mixed 请求数据
 */
function rqst($name, $default = '', $xss_clean = false) {
	global $cfg_opts, $__rqst;
	if ($__rqst == null) {
		$__rqst = new Request ( false );
	}
	return $__rqst->get ( $name, $default, $xss_clean );
}
/**
 * 读取多个请求数据
 *
 * <code>
 * $names = array('name','age'=>20,'address'=>'shanghai');
 * $values = rqsts($names);
 * </code>
 *
 * @global array 框架配置
 * @global Request 请求实例
 * @see Request::gets
 * @param array $names
 * 变量数组
 * @param boolean $xss_clean        	
 * @return array 值数组
 */
function rqsts($names, $xss_clean = false) {
	global $cfg_opts, $__rqst;
	if ($__rqst == null) {
		$__rqst = new Request ( false );
	}
	return $__rqst->gets ( $names, $xss_clean );
}
/**
 * 请求中是否有变量$name
 *
 * @global array 框架配置
 * @global Request 请求实例
 * @param string $name
 * 变量名
 * @return boolean 如果有返回true,反之false
 */
function rqset($name) {
	global $cfg_opts, $__rqst;
	if ($__rqst == null) {
		$__rqst = new Request ( false );
	}
	return $__rqst->has ( $name );
}
/**
 * 
 * 保留本次请求
 */
function rqsave($name) {
	global $cfg_opts, $__rqst;
	if ($__rqst == null) {
		$__rqst = new Request ( false );
	}
	return $__rqst->save ( $name );
}
/**
 * 
 * 恢复上一次保留的请款数据
 */
function rqrestore($name, $del = true) {
	global $cfg_opts, $__rqst;
	if ($__rqst == null) {
		$__rqst = new Request ( false );
	}
	return $__rqst->restore ( $name, $del );
}
function rqdel($name) {
	global $cfg_opts, $__rqst;
	if ($__rqst == null) {
		$__rqst = new Request ( false );
	}
	return $__rqst->delete ( $name );
}
/**
 * 读取整型数据
 *
 * 使用{@link rqst()}读取数据,然后强制转换成整形并返回.
 *
 * @see rqst
 * @uses rqst 从请求中读取数据
 * @param string $name
 * 变量名
 * @param int $default
 * 默认值
 * @return int 请求数据
 */
function irqst($name, $default = 0) {
	return intval ( rqst ( $name, $default, true ) );
}
/**
 * 读取浮点型数据
 *
 * 使用{@link rqst()}读取数据,然后强制转换成浮点型并返回.
 *
 * @see rqst
 * @uses rqst 从请求中读取数据
 * @param string $name
 * 变量名
 * @param float $default
 * 默认值
 * @return float 请求数据
 */
function frqst($name, $default = 0) {
	return floatval ( rqst ( $name, $default, true ) );
}
/**
 * 从COOKIE读取数据
 *
 * @global array
 * @global Request
 * @see Request::cookie
 * @param string $name
 * 变量值
 * @param mixed $default
 * 默认值
 * @return mixed 值
 */
function cookie($name, $default = '') {
	global $cfg_opts, $__rqst;
	if ($__rqst == null) {
		$__rqst = new Request ( false );
	}
	return $__rqst->cookie ( $name, $default );
}
/**
 * 设置COOKIE.
 *
 * 当$value=null或$expire小于0时从COOKIE中删除$name.
 *
 * @global array
 * @global Request
 * @see Request::setCookie
 * @param string $name
 * 变量名
 * @param mixed $value
 * 值
 * @param int $expire
 * 过期时间
 * @param string $domain 作用域
 */
function scookie($name, $value = null, $expire = null, $domain = '') {
	global $cfg_opts, $__rqst;
	if ($__rqst == null) {
		$__rqst = new Request ( false );
	}
	$__rqst->setCookie ( $name, $value, $expire, $domain );
}
/**
 * 获取uri
 *
 * 当前请求的uri,用于处理不同服务器在$_SERVER中定义的不同变量.
 *
 * @return string 当前页面的uri
 */
function request_uri() {
	if (isset ( $_SERVER ['REQUEST_URI'] )) {
		$uri = $_SERVER ['REQUEST_URI'];
	} else {
		if (isset ( $_SERVER ['argv'] )) {
			$uri = $_SERVER ['PHP_SELF'] . '?' . $_SERVER ['argv'] [0];
		} else {
			$uri = $_SERVER ['PHP_SELF'] . '?' . $_SERVER ['QUERY_STRING'];
		}
	}
	return $uri;
}
/** 
 * session id
 *
 * @return string 当前会话ID
 */
function sess_id() {
	global $__sess;
	
	if ($__sess == null) {
		$__sess = __init_session ();
	}
	
	if ($__sess) {
		return $__sess->id ();
	}
	return "";
}

/**
 * 设置SESSIOIN.
 *
 * 当$value=null时从SESSION中删除$name对应的值
 *
 * @global ISession 系统SESSION实例
 * @see ISession::add
 * @param string $name
 * 值名
 * @param mixed $value
 * 值
 */
function sess_add($name, $value = null) {
	global $__sess;
	if ($__sess == null) {
		$__sess = __init_session ();
	}
	if ($__sess) {
		$__sess->add ( $name, $value );
	}
}
/**
 * 从SESSION中取值
 *
 * 如果未设置,则返回默认值 $default
 *
 * @global ISession 系统SESSION实例
 * @see ISession::get
 * @param string $name
 * 值名
 * @param mixed $default
 * 默认值
 * @return mixed SESSION中的值
 */
function sess_get($name, $default = "") {
	global $__sess;
	if ($__sess == null) {
		$__sess = __init_session ();
	}
	if ($__sess) {
		return $__sess->get ( $name, $default );
	}
	return null;
}
/**
 * 从SESSION中删除变量$name
 *
 * 使用null值调用sess_add以达到从SESSION中删除变量的目的.
 *
 * @see sess_add
 * @uses sess_add 使用null值调用sess_add
 * @param string $name        	
 */
function sess_del($name, $default = '') {
	$value = sess_get ( $name, $default );
	sess_add ( $name, null );
	return $value;
}
/**
 * 关闭会话
 *
 * @global ISession 全局SESSION实例
 */
function sess_close() {
	global $__sess;
	if ($__sess) {
		$__sess->close ();
	}
}

/**
 * 销毁SESSION
 *
 * @global ISession 全局SESSION实例
 * @see ISession::destroy
 */
function sess_destroy() {
	global $__sess;
	if ($__sess == null) {
		$__sess = __init_session ();
	}
	if ($__sess) {
		$__sess->destroy ();
		$__sess = null;
	}
}
/**
 * 发送邮件
 *
 * @param array $to
 * 接收人
 * @param string $subject
 * 主题
 * @param string $content
 * 正文
 * @param array $attachments
 * 附件
 * @param
 * string 正文类型
 * @return boolean true发送成功,如果失败false
 */
function sendmail($to, $subject, $message, $attachments = array(), $type = '') {
	global $__mailer;
	if ($__mailer == null) {
		$__mailer = apply_filter ( 'get_sys_mailer', $__mailer );
	}
	if ($__mailer && $__mailer instanceof IMailer) {
		if (! empty ( $type )) {
			$__mailer->setMessageType ( $type );
		}
		return $__mailer->send ( $to, $subject, $message, $attachments );
	}
	return false;
}
/**
 * 缓存数据
 *
 * 如果全局缓存实例为null,则创建它.
 *
 * @global ICache 全局缓存实例.
 * @uses __init_cache 创建全局缓存实例
 * @param string $key
 * 缓存唯一键值
 * @param mixed $value
 * 要缓存的数据
 * @param int $expire
 * 缓存时间,默认为3600不缓存.
 * @param string $group
 * 缓存组,默认为default
 */
function cache_add($key, $value, $expire = 3600, $group = 'default') {
	global $__cache;
	if ($__cache == null) {
		$__cache = __init_cache ();
	}
	if ($__cache) {
		return $__cache->add ( $key, $value, $expire, $group );
	}
	return false;
}
/**
 * 从缓存中取数据
 *
 * 如果全局缓存实例为null,则创建它.
 *
 * @global ICache 全局缓存实例.
 * @uses __init_cache 创建全局缓存实例
 * @param string $key
 * 缓存唯一键值
 * @param string $group
 * 缓存组,默认为default
 * @return mixed 缓存数据,如果未命中则返回null
 */
function cache_get($key, $group = 'default') {
	global $__cache;
	if ($__cache == null) {
		$__cache = __init_cache ();
	}
	if ($__cache) {
		return $__cache->get ( $key, $group );
	}
	return null;
}
/**
 * 删除一个缓存
 *
 * 如果全局缓存实例为null,则创建它.
 *
 * @global ICache 全局缓存实例.
 * @uses __init_cache 创建全局缓存实例
 * @param string $key
 * 缓存唯一键值
 * @param string $group
 * 缓存组,默认为default
 * @return mixed
 */
function cache_delete($key, $group = 'default') {
	global $__cache;
	if ($__cache == null) {
		$__cache = __init_cache ();
	}
	if ($__cache) {
		return $__cache->delete ( $key, $group );
	}
}
/**
 * 清空组内所有缓存
 *
 * 如果全局缓存实例为null,则创建它.
 *
 * @global ICache 全局缓存实例.
 * @uses __init_cache 创建全局缓存实例
 * @param boolean $check
 * 清空前是否检查过期
 * @param string $group
 * 缓存组,默认为default
 * @return mixed
 */
function cache_clear($check = true, $group = 'default') {
	global $__cache;
	if ($__cache == null) {
		$__cache = __init_cache ();
	}
	if ($__cache) {
		return $__cache->clear ( $check, $group );
	}
}
/**
 * 初始化session
 *
 * @global ISession 全局SESSION实例
 * @uses apply_filter 通知插件提供SESSION实例
 * @return ISession
 */
function __init_session() {
	global $__sess;
	if ($__sess == null) {
		$__sess = apply_filter ( 'get_session_driver', $__sess );
	}
	return $__sess;
}
/**
 * 取得RBAC权限控制实例
 *
 * @global IRbac
 * @return IRbac
 */
function get_rbac_driver() {
	global $__rbac;
	if ($__rbac == null) {
		$__rbac = apply_filter ( 'get_rbac_driver', $__rbac );
	}
	return $__rbac;
}
/**
 * 初始化cache
 *
 * @global ICache 缓存实例
 * @uses apply_filter 通知插件提供缓存实例
 * @return ICache
 */
function __init_cache() {
	global $__cache;
	if ($__cache == null) {
		$__cache = apply_filter ( 'get_cache_driver', $__cache );
	}
	return $__cache;
}
/**
 * 
 * 删除目录
 * @param string $dir
 */
function rmdirs($dir) {
	$hd = @opendir ( $dir );
	if ($hd) {
		while ( ($file = readdir ( $hd )) != false ) {
			if ($file == '.' || $file == '..') {
				continue;
			}
			if (is_dir ( $dir . DS . $file )) {
				rmdirs ( $dir . DS . $file );
			} else {
				@unlink ( $dir . DS . $file );
			}
		}
		closedir ( $hd );
		@rmdir ( $dir );
	}
	return true;
}
/**
 * 导出路径.
 *
 * 用于类自动加载,每个插件或模块可以自己的引导脚本中调用以此向系统导出路径中添加类路径.
 *
 * @global array 系统类路径
 * @param string $base
 * 以绝对路径提供的文件路径或目录路径
 * @param array $paths
 * 基于$base的目录名
 */
function exportcp($base, $paths = array('classes','models')) {
	global $__exports;
	$base = is_dir ( $base ) ? $base : dirname ( $base );
	if(is_string($paths)){
		$paths = array($paths);
	}
	if (! empty ( $paths )) {
		foreach ( $paths as $p ) {
			$cp = $base . DS . $p;
			if (is_dir ( $cp ) && ! in_array ( $cp, $__exports )) {
				$__exports [] = $cp;
			}
		}
	} else {
		if (is_dir ( $base ) && ! in_array ( $base, $__exports )) {
			$__exports [] = $base;
		}
	}
}

/**
 * 导入文件
 *
 * 作用于include相同
 *
 * @param string $relative
 * 相对路径
 * @param array|string $files
 * 要导入的文件
 */
function _i($relative, $files) {
	$path = dirname ( $relative );
	$files = is_array ( $files ) ? $files : array ($files );
	foreach ( $files as $f ) {
		if (! empty ( $f ) && is_file ( $path . DS . $f )) {
			include $path . DS . $f;
		}
	}
}
/**
 * Retrieve list of allowed mime types and file extensions.
 *
 *
 * @return array Array of mime types keyed by the file extension regex
 * corresponding to those types.
 */
function get_allowed_mime_types() {
	static $mimes = false;
	if (! $mimes) {
		// Accepted MIME types are set here as PCRE unless provided.
		$mimes = apply_filter ( 'upload_mimes', array ('jpg|jpeg|jpe' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', 'bmp' => 'image/bmp', 'tif|tiff' => 'image/tiff', 'ico' => 'image/x-icon', 'asf|asx|wax|wmv|wmx' => 'video/asf', 'avi' => 'video/avi', 'divx' => 'video/divx', 'flv' => 'video/x-flv', 'mov|qt' => 'video/quicktime', 'mpeg|mpg|mpe' => 'video/mpeg', 'txt|asc|c|cc|h' => 'text/plain', 'csv' => 'text/csv', 'tsv' => 'text/tab-separated-values', 'ics' => 'text/calendar', 'rtx' => 'text/richtext', 'css' => 'text/css', 'htm|html' => 'text/html', 'mp3|m4a|m4b' => 'audio/mpeg', 'mp4|m4v' => 'video/mp4', 'ra|ram' => 'audio/x-realaudio', 'wav' => 'audio/wav', 'ogg|oga' => 'audio/ogg', 'ogv' => 'video/ogg', 'mid|midi' => 'audio/midi', 'wma' => 'audio/wma', 'mka' => 'audio/x-matroska', 'mkv' => 'video/x-matroska', 'rtf' => 'application/rtf', 'js' => 'application/javascript', 'pdf' => 'application/pdf', 'doc|docx' => 'application/msword', 'pot|pps|ppt|pptx|ppam|pptm|sldm|ppsm|potm' => 'application/vnd.ms-powerpoint', 'wri' => 'application/vnd.ms-write', 'xla|xls|xlsx|xlt|xlw|xlam|xlsb|xlsm|xltm' => 'application/vnd.ms-excel', 'mdb' => 'application/vnd.ms-access', 'mpp' => 'application/vnd.ms-project', 'docm|dotm' => 'application/vnd.ms-word', 'pptx|sldx|ppsx|potx' => 'application/vnd.openxmlformats-officedocument.presentationml', 'xlsx|xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml', 'docx|dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml', 'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote', 'swf' => 'application/x-shockwave-flash', 'class' => 'application/java', 'tar' => 'application/x-tar', 'zip' => 'application/zip', 'gz|gzip' => 'application/x-gzip', 'rar' => 'application/rar', '7z' => 'application/x-7z-compressed', 'exe' => 'application/x-msdownload', // openoffice
// formats
		'odt' => 'application/vnd.oasis.opendocument.text', 'odp' => 'application/vnd.oasis.opendocument.presentation', 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 'odg' => 'application/vnd.oasis.opendocument.graphics', 'odc' => 'application/vnd.oasis.opendocument.chart', 'odb' => 'application/vnd.oasis.opendocument.database', 'odf' => 'application/vnd.oasis.opendocument.formula' ) );
	}
	return $mimes;
}

/** 
 * 分页
 *
 *
 * @param int $total
 * 记录总数
 * @param int $limit
 * 每页记录数,默认为15
 * @param int $cur
 * 当前是第几页,默认从URL获取
 * @param string $param
 * 分页参数,默认为pid
 * @param int $pp
 * 每页显示几条页数导航,默认为10
 * @param string $url
 * 分页链接,不需要添加参数
 * @return string 分页HTML片断
 */
function paging($total, $limit = 15, $cur = null, $param = 'pid', $pp = 10, $url = null) {
	global $__url;
	$cur != null or $cur = irqst ( $param, 1 );
	if ($url == null) {
		$url = BASE_URL . $__url;
	} else {
		$url = BASE_URL . $url;
	}
	$limit = empty ( $limit ) ? 10 : $limit;
	$total = intval ( $total );
	$tp = ceil ( $total / $limit ); // 一共有多少页
	$qs = preg_replace ( '/[&\?]?' . $param . '=\d*/', '', $url );
	$qs .= (strpos ( $qs, '?' ) === false ? '?' : '&') . $param . '=';
	$url = $qs;
	$pager = array ('<ul>' );
	$pager [] = sprintf ( '<li><a>共%s条记录,每页%d条记录,', $total, $limit );
	$_cp = $cur * $limit;
	$_cp = $_cp > $total ? $total : $_cp;
	if ($_cp > 0) {
		$pager [] = sprintf ( '第%s~%s条记录</a></li>', ($cur - 1) * $limit + 1, $_cp );
	} else {
		$pager [] = '</a></li>';
	}
	if ($tp > 1) {
		if ($cur == 1) { // 当前在第一页
			$pager [] = '<li><a>首</a></li><li><a>上</a></li>';
		} else {
			$pager [] = sprintf ( '<li><a title="第一页" href="%s">首</a></li><li><a title="上一页" href="%s">上</a></li>', $url . '1', $url . ($cur - 1) );
		}
		// 向前后各多少页
		$sp = $pp % 2 == 0 ? $pp / 2 : ($pp - 1) / 2;
		if ($cur <= $sp) {
			$start = 1;
			$end = $pp;
			$end = $end > $tp ? $tp : $end;
		} else {
			$start = $cur - $sp;
			$end = $cur + $sp;
			if ($pp % 2 == 0) {
				$end -= 1;
			}
			if ($end >= $tp) {
				$start -= ($end - $tp);
				$start > 0 or $start = 1;
				$end = $tp;
			}
		}
		for($i = $start; $i <= $end; $i ++) {
			if ($i == $cur) {
				$pager [] = sprintf ( '<li class="active"><a>%d</a></li>', $i );
			} else {
				$pager [] = sprintf ( '<li><a href="%s" title="第%d页">%d</a></li>', $url . $i, $i, $i );
			}
		}
		if ($cur == $tp) {
			$pager [] = '<li><a>下</a></li><li><a>尾</a></li>';
		} else {
			$pager [] = sprintf ( '<li><a title="下一页" href="%s">下</a></li><li><a title="最后一页" href="%s">尾</a></li>', $url . ($cur + 1), $url . $tp );
		}
	}
	$pager [] = '</ul>';
	return implode ( "", $pager );
}
function custom_page_info($paging, $args) {
	global $__url;
	$url = the_safe_url ( $paging ['url'] );
	$cur = $paging ['cur'];
	$total = $paging ['total'];
	$per = $paging ['per'];
	$ext = $paging ['ext'];
	
	$tp = ceil ( $total / $per ); // 一共有多少页
	

	$pager = array ();
	if ($tp < 2) {
		return $pager;
	}
	$pager ['total'] = $tp;
	$pager ['count'] = $total;
	if ($cur == 1) { // 当前在第一页
		$pager ['first'] = '#';
		$pager ['prev'] = '#';
	} else {
		$pager ['first'] = BASE_URL . $__url;
		$pager ['prev'] = $cur == 2 ? BASE_URL . $__url : $url . ($cur - 1) . $ext;
	}
	// 向前后各多少页
	$pp = isset ( $args ['pp'] ) ? intval ( $args ['pp'] ) : 10;
	$sp = $pp % 2 == 0 ? $pp / 2 : ($pp - 1) / 2;
	if ($cur <= $sp) {
		$start = 1;
		$end = $pp;
		$end = $end > $tp ? $tp : $end;
	} else {
		$start = $cur - $sp;
		$end = $cur + $sp;
		if ($pp % 2 == 0) {
			$end -= 1;
		}
		if ($end >= $tp) {
			$start -= ($end - $tp);
			$start > 0 or $start = 1;
			$end = $tp;
		}
	}
	for($i = $start; $i <= $end; $i ++) {
		if ($i == $cur) {
			$pager [$i] = '#';
		} else if ($i == 1) {
			$pager [$i] = BASE_URL . $__url;
		} else {
			$pager [$i] = $url . $i . $ext;
		}
	}
	if ($cur == $tp) {
		$pager ['next'] = '#';
		$pager ['last'] = '#';
	} else {
		$pager ['next'] = $url . ($cur + 1) . $ext;
		$pager ['last'] = $url . $tp . $ext;
	}
	return $pager;
}
/**
 * 表格排序
 *
 * @param string $text
 * 表头文字
 * @param string $url
 * url,无参数的URL
 * @param string $filed
 * 排序字段
 * @param string $sort
 * 默认排序
 * @return string
 */
function sortheader($text, $url, $filed, $sort = 'd') {
	global $__url;
	if ($url == null) {
		$url = $__url;
	}
	$stext = '';
	if (preg_match ( '/_sf=' . $filed . '/', $_SERVER ['QUERY_STRING'] )) {
		if (preg_match ( '/_sd=([ad])/', $_SERVER ['QUERY_STRING'], $_sort )) {
			$sort = $_sort [1] == 'a' ? 'd' : 'a';
			$stext = $_sort [1] == 'a' ? '<i class="asc"></i>' : '<i class="desc"></i>';
		}
	}
	! empty ( $stext ) or $stext = '<i class="sdir"></i>';
	$qs = preg_replace ( array ('/[&\?]?_sf=[^&]*/', '/[&\?]?_sd=[^&]*/' ), array ('', '' ), $url );
	$ss = '_sf=' . $filed . '&_sd=' . $sort;
	$qs .= (strpos ( $qs, '?' ) === false ? '?' : '&') . $ss;
	return sprintf ( '<div class="sortheader"><a href="%s">%s</a>%s</div>', $qs, $text, $stext );
}
/** 
 *
 * 得到排序信息
 *
 * @param string $field        	
 * @param string $dir        	
 * @return array('filed'=>$filed,'dir'=>$dir)
 */
function sortinfo($field = '', $dir = 'd') {
	$info = array ();
	$info ['field'] = rqst ( '_sf', $field );
	$info ['dir'] = rqst ( '_sd', $dir );
	return $info;
}
function sortargs($sortinfo) {
	return '_sf=' . $sortinfo ['field'] . '&_sd=' . $sortinfo ['dir'];
}
/**
 * 如果$value等$value1,返回$v1,否则返回$v2
 *
 * @param mixed $value        	
 * @param mixed $value1        	
 * @param mixed $v1        	
 * @param mixed $v2        	
 * @return mixed
 */
function ife($value, $value1, $v1, $v2 = '') {
	return $value == $value1 ? $v1 : $v2;
}
/**
 * 如果$value为空(empty),则返回$v1,否则返回$v2
 *
 * @param mixed $value        	
 * @param mixed $v1        	
 * @param mixed $v2        	
 */
function ifp($value, $v1, $v2 = '') {
	return empty ( $value ) ? $v1 : $v2;
}
/**
 * 根据宽高生成缩略图文件名
 *
 * @param string $filename
 * 原始文件名
 * @param int $w        	
 * @param int $h        	
 * @return string
 */
function get_thumbnail_filename($filename, $w, $h) {
	$pos = strrpos ( $filename, '.' );
	if ($pos === false) {
		return false;
	}
	$shortname = substr ( $filename, 0, $pos );
	$ext = substr ( $filename, $pos );
	return $shortname . "-{$w}x{$h}{$ext}";
}
function the_thumbnail_src($src, $w, $h) {
	$thumbfile = get_thumbnail_filename ( $src, $w, $h );
	if (file_exists ( WWW_ROOT . $thumbfile )) {
		return BASE_URL . $thumbfile;
	} else {
		return BASE_URL . $src;
	}
}
/** 
 *
 * 只保留URL中部分参数
 *
 * @param string $url        	
 * @param array $include
 * 要保留的参数
 * @return string
 */
function keepargs($url, $include = array()) {
	$urls = explode ( '?', $url );
	if (count ( $urls ) < 2) {
		return $url;
	}
	$kargs = array ();
	foreach ( $include as $arg ) {
		if (preg_match ( '/' . $arg . '=([^&]+)/', $urls [1], $m )) {
			$kargs [] = $m [0];
		}
	}
	if (! empty ( $kargs )) {
		$urls [1] = implode ( '&', $kargs );
		return implode ( '?', $urls );
	} else {
		return $urls [0];
	}
}
/** 
 *
 * 去除URL中的参数
 *
 * @param
 * string url
 * @param
 * array 要去除的参数
 * @return string
 */
function unkeepargs($url, $exclude = array()) {
	$regex = array ();
	$rpm = array ();
	if (is_string ( $exclude )) {
		$exclude = array ($exclude );
	}
	foreach ( $exclude as $ex ) {
		$regex [] = '/&?' . $ex . '=[^&]*/';
		$rpm [] = '';
	}
	return preg_replace ( $regex, $rpm, $url );
}
/** 
 * 安全ID
 *
 * @param string $ids
 * 以$sp分隔的id列表,只能是大与0的整形
 * @param string $sp
 * 分隔符
 * @param boolean $array
 * 是否返回数组
 * @return mixed
 */
function safe_ids($ids, $sp = ",", $array = false) {
	if (empty ( $ids )) {
		return $array ? array () : null;
	}
	$_ids = explode ( $sp, $ids );
	$ids = array ();
	foreach ( $_ids as $id ) {
		if (preg_match ( '/^[1-9]\d*$/', $id )) {
			$ids [] = $id;
		}
	}
	if ($array === false) {
		return empty ( $ids ) ? null : implode ( $sp, $ids );
	} else {
		return empty ( $ids ) ? array () : $ids;
	}
}
function getTreeTableRows($items, $ufield, $field) {
	$cates = array ();
	foreach ( $items as $item ) {
		if ($item [$ufield] == 0) { // 顶级栏目
			$item ['tree_id'] = 'c-' . $item [$field];
		} else {
			$item ['tree_id'] = 'c-' . $item [$field];
			$item ['tree_clz'] = 'hide item-of-c-' . $item [$ufield];
		}
		$cates [] = $item;
	}
	return $cates;
}
/**
 * 可读的size
 * @param int $size
 * @return string
 */
function readable_size($size) {
	if ($size < 1024) {
		return $size . 'B';
	} else if ($size < 1048576) {
		return number_format ( $size / 1024, 2 ) . 'K';
	} else if ($size < 1073741824) {
		return number_format ( $size / 1048576, 2 ) . 'M';
	} else {
		return number_format ( $size / 1073741824, 2 ) . 'G';
	}
}
/**
 * 生成带参数的页面url 
 */
function build_page_url($url, $args) {
	static $params = null;
	if (is_null ( $params )) {
		parse_str ( $_SERVER ['QUERY_STRING'], $params );
		unset ( $params ['__url'] );
	}
	$url = explode ( '?', $url );
	$url = $url [0];
	$pargs = $params;
	if (! empty ( $args )) {
		$argnames = array_shift ( $args );
		$argnames = explode ( ',', $argnames );
		$i = 0;
		foreach ( $argnames as $n ) {
			if (preg_match ( '#^\-([a-z_][a-z\d_-]*)$#', $n, $m )) {
				unset ( $pargs [$m [1]] );
			} else {
				$pargs [$n] = $args [$i ++];
			}
		}
	}
	if (! empty ( $pargs ) && ! preg_match ( '/.*#$/', $url )) {
		if (strpos ( $url, '?' ) === false) {
			return $url . '?' . http_build_query ( $pargs );
		} else {
			return $url . '&' . http_build_query ( $pargs );
		}
	} else {
		return $url;
	}
}
/**
 * 来自ucenter的加密解密函数
 * @param string $string 要解（加）密码字串
 * @param string $operation DECODE|ENCODE 解密|加密
 * @param string $key 密码
 * @param int $expiry 超时
 */
function ntzauthcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
	$ckey_length = 4;
	
	$key = md5 ( $key ? $key : COOKIE_KEY );
	$keya = md5 ( substr ( $key, 0, 16 ) );
	$keyb = md5 ( substr ( $key, 16, 16 ) );
	$keyc = $ckey_length ? ($operation == 'DECODE' ? substr ( $string, 0, $ckey_length ) : substr ( md5 ( microtime () ), - $ckey_length )) : '';
	
	$cryptkey = $keya . md5 ( $keya . $keyc );
	$key_length = strlen ( $cryptkey );
	
	$string = $operation == 'DECODE' ? base64_decode ( substr ( $string, $ckey_length ) ) : sprintf ( '%010d', $expiry ? $expiry + time () : 0 ) . substr ( md5 ( $string . $keyb ), 0, 16 ) . $string;
	$string_length = strlen ( $string );
	
	$result = '';
	$box = range ( 0, 255 );
	
	$rndkey = array ();
	for($i = 0; $i <= 255; $i ++) {
		$rndkey [$i] = ord ( $cryptkey [$i % $key_length] );
	}
	
	for($j = $i = 0; $i < 256; $i ++) {
		$j = ($j + $box [$i] + $rndkey [$i]) % 256;
		$tmp = $box [$i];
		$box [$i] = $box [$j];
		$box [$j] = $tmp;
	}
	
	for($a = $j = $i = 0; $i < $string_length; $i ++) {
		$a = ($a + 1) % 256;
		$j = ($j + $box [$a]) % 256;
		$tmp = $box [$a];
		$box [$a] = $box [$j];
		$box [$j] = $tmp;
		$result .= chr ( ord ( $string [$i] ) ^ ($box [($box [$a] + $box [$j]) % 256]) );
	}
	
	if ($operation == 'DECODE') {
		if ((substr ( $result, 0, 10 ) == 0 || substr ( $result, 0, 10 ) - time () > 0) && substr ( $result, 10, 16 ) == substr ( md5 ( substr ( $result, 26 ) . $keyb ), 0, 16 )) {
			return substr ( $result, 26 );
		} else {
			return '';
		}
	} else {
		return $keyc . str_replace ( '=', '', base64_encode ( $result ) );
	}
}
/**
 * error log
 */
function elog($msg) {
	if (LOG_LEVEL >= LERROR) {
		$msg = date ( "[Y-m-d H:i:s]" ) . " ERROR > " . request_uri () . "\n\t{$msg} \n";
		@error_log ( $msg, 3, TMP_PATH . 'error.log' );
	}
}
/**
 * info log
 */
function ilog($msg) {
	if (LOG_LEVEL >= LINFO) {
		$msg = date ( "[Y-m-d H:i:s]" ) . " INFO > " . request_uri () . "\n\t{$msg} \n";
		@error_log ( $msg, 3, TMP_PATH . 'error.log' );
	}
}
/**
 * warn log
 */
function wlog($msg) {
	if (LOG_LEVEL >= LWARN) {
		$msg = date ( "[Y-m-d H:i:s]" ) . " WARN > " . request_uri () . "\n\t{$msg} \n";
		@error_log ( $msg, 3, TMP_PATH . 'error.log' );
	}
}
/**
 * debug log
 */
function dlog($msg) {
	if (LOG_LEVEL >= LDEBUG) {
		$msg = date ( "[Y-m-d H:i:s]" ) . " DEBUG > " . request_uri () . "\n\t{$msg} \n";
		@error_log ( $msg, 3, TMP_PATH . 'error.log' );
	}
}
